Housekeeping

Loading in data

OTU

ANALYSIS

OTU diversity and such

OTU_table.t<-transpose.OTU(OTU_table)
ab<-table(unlist(OTU_table.t))
ab[1:20] 

barplot(log(ab), las=1, xlab = "Abundand in matrix", 
        ylab = "log (frequency)", 
        ylim = c(0, max(log(ab))+2))


row.names(OTU_table)<-OTU_table$OTU_ID
OTU_table.OTU_ID<-OTU_table$OTU_ID
OTU_table$OTU_ID<-NULL
OTU_table<-OTU_table[,colSums(OTU_table[,c(1:(length(colnames(OTU_table))-1))])!=0]
OTU_table.t<-transpose.OTU(OTU_table)


OTU_table.ns<-OTU_table[rowSums(OTU_table[,c(1:(length(OTU_table)-1))])!=1,]
dim(OTU_table)
dim(OTU_table.ns)


OTU_table<-OTU_table.ns
OTU_table.t<-transpose.OTU(OTU_table)

# Seperate taxonomy
OTU_table$taxonomy<-as.character(OTU_table$taxonomy)

tax.classes <- c("kingdom", "phylum", "class", "order", "family", "genus", "species")
OTU_table.tax <- col.splitup(OTU_table, col="taxonomy", sep="; ",drop=TRUE, names=tax.classes)
OTU_table.tax$taxonomy<-OTU_table$taxonomy

Making the metadata

Diversity Model

# Normal?
colnames(OTU.info2)
colnames(OTU.info2)[colnames(OTU.info2)=="Annual.mean.temperature...C."] <- "AnnualMeanTemperature"
colnames(OTU.info2)[colnames(OTU.info2)=="Mean.diurnal.temperature.range..mean.period.max.min.....C."] <- "MeanDiurnalTemperatureRange"
colnames(OTU.info2)[colnames(OTU.info2)=="Temperature.seasonality..C.of.V."] <- "TemperatureSeasonality"
colnames(OTU.info2)[colnames(OTU.info2)=="Max.temperature.of.warmest.week...C."] <- "MaxTemperature"
colnames(OTU.info2)[colnames(OTU.info2)=="Min.temperature.of.coldest.week...C."] <- "MinTemperature"
colnames(OTU.info2)[colnames(OTU.info2)=="Annual.precipitation..mm."] <- "AnnualPrecipitation"
colnames(OTU.info2)[colnames(OTU.info2)=="Precipitation.of.wettest.week..mm."] <- "MaxPrecipitation"
colnames(OTU.info2)[colnames(OTU.info2)=="Precipitation.of.driest.quarter..mm."] <- "MinPrecipitation"
colnames(OTU.info2)[colnames(OTU.info2)=="Precipitation.of.coldest.quarter..mm."] <- "ColdestPrecipitation"
colnames(OTU.info2)[colnames(OTU.info2)=="Precipitation.seasonality..C.of.V."] <- "PrecipitationSeasonality"


Mydata<-OTU.info2[,c(1:6,8:10,16:17,19,21,23)]
Y<-Mydata[,c(8:length(Mydata))]
covar_cor = cor(Y)
corrplot.mixed(covar_cor, upper = "ellipse", lower = "number")
Mydata_PCA = dudi.pca(df = Y, scannf = FALSE, nf = 2, center = TRUE, scale = TRUE)
Mydata_PCA$co
s.corcircle(Mydata_PCA$co)
Mydata_PCA$eig/sum(Mydata_PCA$eig)
colnames(Mydata)

Mydata$Lat <- scale(Mydata$Lat)
Mydata$Long <- scale(Mydata$Long)
Mydata$AnnualPrecipitation <- scale(Mydata$AnnualPrecipitation)
Mydata$AnnualMeanTemperature <- scale(Mydata$AnnualMeanTemperature)
Mydata$PrecipitationSeasonality <- scale(Mydata$PrecipitationSeasonality)
Mydata$TemperatureSeasonality  <- scale(Mydata$TemperatureSeasonality)
Mydata$MeanDiurnalTemperatureRange<- scale(Mydata$MeanDiurnalTemperatureRange)
Mydata$MinTemperature <- scale(Mydata$MinTemperature)
Mydata$MaxTemperature <- scale(Mydata$MaxTemperature)



mod1<-lm(mean.Alpha.div ~ Lat + Long + AnnualPrecipitation + AnnualMeanTemperature + PrecipitationSeasonality + TemperatureSeasonality  + MeanDiurnalTemperatureRange+ MinTemperature + MaxTemperature , data = Mydata)

car::qqp(OTU.info2$mean.Alpha.div, "norm")
plot(density(OTU.info2$mean.Alpha.div))
shapiro.test(OTU.info2$mean.Alpha.div)
bptest(mod1)
plot(mod1)

# Is endophyte diversity driven by any climatic data? NO
mod1.mLat<-update(mod1,.~. - Lat)
anova(mod1,mod1.mLat)

mod1.mLong<-update(mod1.mLat,.~. - Long)
anova(mod1.mLat,mod1.mLong)

mod1.mAnnualPrecipitation<-update(mod1.mLong,.~. - AnnualPrecipitation)
anova(mod1.mLong,mod1.mAnnualPrecipitation)

mod1.mAnnualMeanTemperature<-update(mod1.mAnnualPrecipitation,.~. - AnnualMeanTemperature)
anova(mod1.mAnnualPrecipitation,mod1.mAnnualMeanTemperature)

mod1.mPrecipitationSeasonality<-update(mod1.mAnnualMeanTemperature,.~. - PrecipitationSeasonality)
anova(mod1.mAnnualMeanTemperature, mod1.mPrecipitationSeasonality)

mod1.mTemperatureSeasonality<-update(mod1.mPrecipitationSeasonality,.~. - TemperatureSeasonality)
anova(mod1.mPrecipitationSeasonality,mod1.mTemperatureSeasonality)

mod1.mMeanDiurnalTemperatureRange<-update(mod1.mTemperatureSeasonality,.~. - MeanDiurnalTemperatureRange)
anova(mod1.mTemperatureSeasonality, mod1.mMeanDiurnalTemperatureRange)

# Min temperature is a significant predictor!
mod1.mMinTemperature<-update(mod1.mMeanDiurnalTemperatureRange,.~. - MinTemperature)
anova(mod1.mMeanDiurnalTemperatureRange, mod1.mMinTemperature)

# Max temperature is a significant predictor!
mod1.mMaxTemperature<-update(mod1.mMinTemperature,.~. - MaxTemperature)
anova(mod1.mMinTemperature, mod1.mMaxTemperature)


mod2<- lm(Alpha.div~Species,data=OTU.info)
summary(mod2)

Composition model

FIGURES

OTU.info$Species<-plyr::revalue(OTU.info$Species, c("Brassica_napus"="Brassica napus", "Brassica_oleracea"="Brassica oleracea","Cratoneuron"="Cratoneuron filicinum","Grimmia"="Grimmia pilifera","Microdesmis"="Microdesmis caseariifolia","Orchid"="Phalaenopsis","Oryza"="Oryza sativa","Paeonia_rockii"="Paeonia rockii","Paeonia_suffruticosa"="Paeonia suffruticosa","Pinus"="Pinus pinaster","Pinus_flexilis"="Pinus flexilis","Pylaisiella"="Pylaisia polyantha","Rothmannia"="Rothmannia macrophylla","Santiria"="Santiria apiculata","Solanum"="Solanum lycopersicum","Vitis"="Vitis vinifera","Zea"="Zea mays"))


# Alpha to secies
Adiv_species_OTU<-ggplot(OTU.info, aes(y=Alpha.div,x=Species))+
  geom_boxplot(aes(color=Species))+
  labs(y="Shannon diversity")+
  theme_katherine()+ theme(axis.text.x = element_text(angle = 90, hjust = 1),legend.position="none")+
  ggtitle("Alpha Diversity of OTUs by Species")
ggsave("Adiv_species.OTU_PLOT.pdf",Adiv_species_OTU)

# RDA
smry <- summary(formulaRDA)
df1  <- data.frame(smry$sites[,1:2])       # PC1 and PC2
df2  <- data.frame(smry$biplot[,1:2])     # loadings for PC1 and PC2
rda.plot <- ggplot(df1, aes(x=RDA1, y=RDA2)) + 
  geom_text(aes(label=rownames(df1)),size=3,position=position_jitter(width=.2,height=.2)) +
  geom_point(aes(alpha=0.3)) +
  geom_hline(yintercept=0, linetype="dotted") +
  geom_vline(xintercept=0, linetype="dotted")  

names<-c("Latitude","Longitude","\nMean Annual Temp", "Diurnal Temp Range", "\nTemp Seasonality", "Max Temp\n", "Min Temp", "Annual Precipitation\n", "Max Precipitation", "Precipitation Seasonality", "Min Precipitation", "Coldest Precipitation    ")
rownames(df2)
(formulaRDA.PLOT<-rda.plot +
  geom_segment(data=df2, aes(x=0, xend=RDA1, y=0, yend=RDA2), 
               color="red", arrow=arrow(length=unit(0.01,"npc"))) +
  geom_text(data=df2, 
            aes(x=RDA1,y=RDA2,label=names,
                hjust=0.5*(1-sign(RDA1)),vjust=0.5*(1-sign(RDA2))), 
            color="red", size=4)+
  coord_cartesian(ylim = c(-0.8, 0.8),xlim = c(-1.3, 1.3)) +theme_katherine()+ theme(legend.position="none"))
ggsave("formulaRDA.OTU_PLOT.pdf",formulaRDA.PLOT)

# NMDS
#Make a matrix with no row or column equal to 0 (do not enclude the env variable (GM COVERAGE))
OTU_table.t2<-merge(OTU_table.t,X, by="SampleID")
OTU_table.t2$SampleID<-NULL
rownames.M<-OTU_table.t2$Species
OTU_table.t2$Species<-NULL
M <- as.matrix(OTU_table.t2)
M[is.na(M)] <- 0
which( colSums(M)==0 )
which( rowSums(M)==0 )

rownames(M) <- rownames.M

dist_M <- vegdist(M, method = "bray", binary = T)
#The metaMDS analysis could have done the distance matrix internally but i would rather control it since i have presence/abscence
meta.nmds <- metaMDS(dist_M, k=2, trymax = 2000)
str(meta.nmds)
stressplot(meta.nmds)

Species<-data.frame(Species=as.factor(rownames.M))
# envfit
envfit <- envfit(meta.nmds, env = Species, perm = 999) #standard envfit
envfit

#data for plotting 
##NMDS points
NMDS.data<-Species 
NMDS.data$NMDS1<-meta.nmds$points[ ,1] 
NMDS.data$NMDS2<-meta.nmds$points[ ,2] 
colnames(NMDS.data)[1] <- "Species"

mult <- 1 #multiplier for the arrows and text for envfit below. You can change this and then rerun the plot command.
library(ggplot2)
(OTU.nmds.gg1 <- ggplot(data = NMDS.data, aes(y = NMDS2, x = NMDS1))+ 
    geom_point( aes(color = NMDS.data$Species), size = 1.5,alpha=0.6)+ 
    coord_cartesian(xlim = c(-0.25,0.25),ylim = c(-0.1,0.1)) + 
    theme_katherine())
ggsave("nmds.OTU_PLOT.pdf",OTU.nmds.gg1)

Functions

ANALYSIS

Functional diversity and such

metagenome_predictions
metagenome_predictions<-metagenome_predictions[,colSums(metagenome_predictions[,])!=0]
metagenome_predictions<-metagenome_predictions[rowSums(metagenome_predictions[,])!=0,]
metagenome_predictions.ns<-metagenome_predictions[,colSums(metagenome_predictions[,])!=1]
dim(metagenome_predictions)
[1]  177 3424
dim(metagenome_predictions.ns)
[1]  177 3407
metagenome_predictions<-metagenome_predictions.ns
Functions<-colnames(metagenome_predictions)
Samples<-rownames(metagenome_predictions)
metagenome_predictions.info<-data.frame(SampleID=Samples, OTU.Alpha.div=rep(NA, length(Samples)),Species=rep(NA, length(Samples)), Function.Alpha.div=rep(NA, length(Samples)))
which(sapply(OTU_table.t, is.character))
named integer(0)
OTU_table.t$SampleID<-NULL
for(i in 1:(length(Samples))){
metagenome_predictions.info$SampleID[i]<-Samples[i]
metagenome_predictions.info$OTU.Alpha.div[i]<-diversity(OTU_table.t[rownames(OTU_table.t)==Samples[i],], index = "shannon", MARGIN = 1, base = exp(1))
metagenome_predictions.info$Function.Alpha.div[i]<-diversity(metagenome_predictions[rownames(metagenome_predictions)==Samples[i],], index = "shannon", MARGIN = 1, base = exp(1))
metagenome_predictions.info$Species[i]<-mapping_file[mapping_file$SampleID==Samples[i],]$Species
}
metagenome_predictions.info$Species<-as.factor(metagenome_predictions.info$Species)
metagenome_predictions.info %>% dplyr::group_by(Species) %>% summarise(mean.OTU.Alpha.div=mean(OTU.Alpha.div),mean.Function.Alpha.div=mean(Function.Alpha.div)) -> metagenome_predictions.info2
metagenome_predictions.info2<-merge(metagenome_predictions.info2, BioDatFull2, by="Species")

Functional diversity model

# Normal?
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Annual.mean.temperature...C."] <- "AnnualMeanTemperature"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Mean.diurnal.temperature.range..mean.period.max.min.....C."] <- "MeanDiurnalTemperatureRange"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Temperature.seasonality..C.of.V."] <- "TemperatureSeasonality"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Max.temperature.of.warmest.week...C."] <- "MaxTemperature"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Min.temperature.of.coldest.week...C."] <- "MinTemperature"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Annual.precipitation..mm."] <- "AnnualPrecipitation"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Precipitation.of.wettest.week..mm."] <- "MaxPrecipitation"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Precipitation.of.driest.quarter..mm."] <- "MinPrecipitation"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Precipitation.of.coldest.quarter..mm."] <- "ColdestPrecipitation"
colnames(metagenome_predictions.info2)[colnames(metagenome_predictions.info2)=="Precipitation.seasonality..C.of.V."] <- "PrecipitationSeasonality"


Mydata<-metagenome_predictions.info2[,c(1:7,9:11,17,18,20,22,24)]
colnames(metagenome_predictions.info2)
Mydata$Lat <- scale(Mydata$Lat)
Mydata$Long <- scale(Mydata$Long)
Mydata$AnnualPrecipitation <- scale(Mydata$AnnualPrecipitation)
Mydata$AnnualMeanTemperature <- scale(Mydata$AnnualMeanTemperature)
Mydata$PrecipitationSeasonality <- scale(Mydata$PrecipitationSeasonality)
Mydata$TemperatureSeasonality  <- scale(Mydata$TemperatureSeasonality)
Mydata$MeanDiurnalTemperatureRange<- scale(Mydata$MeanDiurnalTemperatureRange)
Mydata$MinTemperature <- scale(Mydata$MinTemperature)
Mydata$MaxTemperature <- scale(Mydata$MaxTemperature)



mod3<-lm(mean.Function.Alpha.div ~ Lat + Long + AnnualPrecipitation + AnnualMeanTemperature + PrecipitationSeasonality + TemperatureSeasonality  + MeanDiurnalTemperatureRange+ MinTemperature + MaxTemperature , data = Mydata)

car::qqp(metagenome_predictions.info2$mean.Function.Alpha.div, "norm")
plot(density(metagenome_predictions.info2$mean.Function.Alpha.div))
shapiro.test(metagenome_predictions.info2$mean.Function.Alpha.div)
bptest(mod3)
plot(mod3)
summary(mod3)
# Is endophyte diversity driven by any climatic data? NO
mod3.mLat<-update(mod3,.~. - Lat)
anova(mod3,mod3.mLat)

mod3.mLong<-update(mod3.mLat,.~. - Long)
anova(mod3.mLat,mod3.mLong)

# Annual precipitation is significant! 
mod3.mAnnualPrecipitation<-update(mod3.mLong,.~. - AnnualPrecipitation)
anova(mod3.mLong,mod3.mAnnualPrecipitation)

mod3.mAnnualMeanTemperature<-update(mod3.mLong,.~. - AnnualMeanTemperature)
anova(mod3.mLong,mod1.mAnnualMeanTemperature)

mod3.mPrecipitationSeasonality<-update(mod3.mAnnualMeanTemperature,.~. - PrecipitationSeasonality)
anova(mod3.mAnnualMeanTemperature, mod3.mPrecipitationSeasonality)

# Temperature seasonality is significant!
mod3.mTemperatureSeasonality<-update(mod3.mPrecipitationSeasonality,.~. - TemperatureSeasonality)
anova(mod3.mPrecipitationSeasonality,mod3.mTemperatureSeasonality)

mod3.mMeanDiurnalTemperatureRange<-update(mod3.mTemperatureSeasonality,.~. - MeanDiurnalTemperatureRange)
anova(mod3.mTemperatureSeasonality, mod3.mMeanDiurnalTemperatureRange)

# Min temperature is a SLIGHTLY significant predictor!
mod3.mMinTemperature<-update(mod3.mMeanDiurnalTemperatureRange,.~. - MinTemperature)
anova(mod3.mMeanDiurnalTemperatureRange, mod3.mMinTemperature)


mod3.mMaxTemperature<-update(mod3.mMinTemperature,.~. - MaxTemperature)
anova(mod3.mMinTemperature, mod3.mMaxTemperature)

mod4<- lm(Function.Alpha.div~Species,data=metagenome_predictions.info)
summary(mod4)

Composition model

X<-metagenome_predictions.info[,c(1,3)]
metagenome_predictions2<-metagenome_predictions
metagenome_predictions2$SampleID<-row.names(metagenome_predictions)
metagenome_predictions2<-merge(metagenome_predictions2,X, by="SampleID")
metagenome_predictions2$Species<-as.factor(metagenome_predictions2$Species)

metagenome_predictions2<-aggregate(metagenome_predictions2, by = list(species=metagenome_predictions2$Species), FUN=mean)
metagenome_predictions2$SampleID<-NULL

row.names(metagenome_predictions2)<-metagenome_predictions2$species
metagenome_predictions2$Species<-NULL
metagenome_predictions2$species<-NULL
sum(is.na(metagenome_predictions2))

metagenome_predictions2matched<-metagenome_predictions2[match(rownames(dist_matrix), rownames(metagenome_predictions2)), ]
beta_divMat<- vegdist(metagenome_predictions2matched, "bray",diag=T)


# Are the endophytes more similar in species that are more closely related phylogenically? NO! 
mantel(beta_divMat,dist_matrix)

# are similarity in the endophyte composition driven by climate data?


Mydata$Species<-plyr::revalue(Mydata$Species, c("Brassica_napus"="Brassica napus", "Brassica_oleracea"="Brassica oleracea","Cratoneuron"="Cratoneuron filicinum","Grimmia"="Grimmia pilifera","Microdesmis"="Microdesmis caseariifolia","Orchid"="Phalaenopsis","Oryza"="Oryza sativa","Paeonia_rockii"="Paeonia rockii","Paeonia_suffruticosa"="Paeonia suffruticosa","Pinus"="Pinus pinaster","Pinus_flexilis"="Pinus flexilis","Pylaisiella"="Pylaisia polyantha","Rothmannia"="Rothmannia macrophylla","Santiria"="Santiria apiculata","Solanum"="Solanum lycopersicum","Vitis"="Vitis vinifera","Zea"="Zea mays"))
rownames(Mydata)<-Mydata$Species


metagenome_predictions2$species<-rownames(metagenome_predictions2)
metagenome_predictions2$species<-as.factor(metagenome_predictions2$species)
metagenome_predictions2$species<-plyr::revalue(metagenome_predictions2$species, c("Brassica_napus"="Brassica napus", "Brassica_oleracea"="Brassica oleracea","Cratoneuron"="Cratoneuron filicinum","Grimmia"="Grimmia pilifera","Microdesmis"="Microdesmis caseariifolia","Orchid"="Phalaenopsis","Oryza"="Oryza sativa","Paeonia_rockii"="Paeonia rockii","Paeonia_suffruticosa"="Paeonia suffruticosa","Pinus"="Pinus pinaster","Pinus_flexilis"="Pinus flexilis","Pylaisiella"="Pylaisia polyantha","Rothmannia"="Rothmannia macrophylla","Santiria"="Santiria apiculata","Solanum"="Solanum lycopersicum","Vitis"="Vitis vinifera","Zea"="Zea mays"))
rownames(metagenome_predictions2)<-metagenome_predictions2$species
metagenome_predictions2$species<-NULL


metagenome_predictions2.hell <- decostand(metagenome_predictions2, "hell")


Mydata<-Mydata[match(rownames(metagenome_predictions2), rownames(Mydata)), ]
var <-Mydata[,c(4:15)]

formulaRDA<- rda(metagenome_predictions2.hell ~ Lat   + PrecipitationSeasonality + TemperatureSeasonality + MinTemperature + MaxTemperature+ MaxPrecipitation + ColdestPrecipitation, data=var, scale=F)

head(summary(formulaRDA))
RsquareAdj(formulaRDA)
anova(formulaRDA, permutations=1000)
anovaMARGIN<-anova.cca(formulaRDA, by="margin", permutations=1000)



varpart(metagenome_predictions2.hell, ~Lat + Long, ~ AnnualMeanTemperature + MeanDiurnalTemperatureRange + TemperatureSeasonality + MaxTemperature + MinTemperature, ~ AnnualPrecipitation + PrecipitationSeasonality + MaxPrecipitation+ MinPrecipitation + ColdestPrecipitation, data=var)

FIGURES

ggsave("nmds.FUN_PLOTFAR.pdf",FUNFAR.nmds.gg1)
Saving 7 x 7 in image
LS0tCnRpdGxlOiAiV29ya2luZyB3aXRoIHRoZSBkYXRhIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IGNlcnVsZWFuCiAgICB0b2M6IHllcwotLS0KI0hvdXNla2VlcGluZwoKYGBge3IgTG9hZCBQYWNrYWdlcywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShyZWFkcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobG1lNCkKbGlicmFyeShNQVNTKQpsaWJyYXJ5KE11TUluKQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KGZpdGRpc3RycGx1cykKbGlicmFyeShjYXIpCmxpYnJhcnkoYmJtbGUpCmxpYnJhcnkobGF0dGljZSkKbGlicmFyeShwZXJtdXRlKQpsaWJyYXJ5KGFkZTQpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHBoeWxvc2VxKQpsaWJyYXJ5KFJBTSkKbGlicmFyeSgiQmlvZGl2ZXJzaXR5UiIpCmBgYAoKYGBge3IgSG91c2VrZWVwaW5nLCBpbmNsdWRlPUZBTFNFfQojIFNpbXBsaWZpZWQsIGNsZWFuIHBsb3R0aW5nIHRoZW1lCnRoZW1lX2thdGhlcmluZSA8LSBmdW5jdGlvbiAoKSB7CiAgIHRoZW1lX2J3KCkrCiAgIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsZmFjZT0iYm9sZCIsIHNpemUgPSAyMCksIAogICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwKICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLGZpbGw9IndoaXRlIiksCiAgICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQp9CgpvdmVyZGlzcF9mdW4gPC0gZnVuY3Rpb24obW9kZWwpIHsKICAjIyBudW1iZXIgb2YgdmFyaWFuY2UgcGFyYW1ldGVycyBpbiBhbiBuLWJ5LW4gdmFyaWFuY2UtY292YXJpYW5jZSBtYXRyaXgKICB2cGFycyA8LSBmdW5jdGlvbihtKSB7CiAgICBucm93KG0pICogKG5yb3cobSkgKyAxKS8yCiAgfQogICMgVGhlIG5leHQgdHdvIGxpbmVzIGNhbGN1bGF0ZSB0aGUgcmVzaWR1YWwgZGVncmVlcyBvZiBmcmVlZG9tCiAgbW9kZWwuZGYgPC0gc3VtKHNhcHBseShWYXJDb3JyKG1vZGVsKSwgdnBhcnMpKSArIGxlbmd0aChmaXhlZihtb2RlbCkpCiAgcmRmIDwtIG5yb3cobW9kZWwuZnJhbWUobW9kZWwpKSAtIG1vZGVsLmRmCiAgIyBleHRyYWN0cyB0aGUgUGVhcnNvbiByZXNpZHVhbHMKICBycCA8LSByZXNpZHVhbHMobW9kZWwsIHR5cGUgPSAicGVhcnNvbiIpCiAgUGVhcnNvbi5jaGlzcSA8LSBzdW0ocnBeMikKICBwcmF0IDwtIFBlYXJzb24uY2hpc3EvcmRmCiAgIyBHZW5lcmF0ZXMgYSBwLXZhbHVlLiBJZiBsZXNzIHRoYW4gMC4wNSwgdGhlIGRhdGEgYXJlIG92ZXJkaXNwZXJzZWQuCiAgcHZhbCA8LSBwY2hpc3EoUGVhcnNvbi5jaGlzcSwgZGYgPSByZGYsIGxvd2VyLnRhaWwgPSBGQUxTRSkKICBjKGNoaXNxID0gUGVhcnNvbi5jaGlzcSwgcmF0aW8gPSBwcmF0LCByZGYgPSByZGYsIHAgPSBwdmFsKQp9CgpyZXNpZGZpdCA8LSBmdW5jdGlvbiAobW9kZWwsIGNvbD0iYmxhY2siKSB7CiAgZjwtZml0dGVkKG1vZGVsKQogIHI8LXJlc2lkKG1vZGVsLCB0eXBlPSdwZWFyc29uJykKICBwbG90KGYsIHIsIGNvbD1jb2wsIG1haW49J1Jlc2lkdWFscyB2cy4gRml0dGVkJykKICBMMTwtbG9lc3Mocn5mKQogIGZ2ZWMgPSBzZXEobWluKGYpLG1heChmKSxsZW5ndGgub3V0PTEwMDApCiAgbGluZXMoZnZlYyxwcmVkaWN0KEwxLGZ2ZWMpLGNvbD0ncmVkJykKfQoKc2NhbGVsb2MgPC0gZnVuY3Rpb24obW9kZWwsY29sPSJibGFjayIpIHsKICBmIDwtIGZpdHRlZChtb2RlbCkKICByIDwtIHNxcnQoYWJzKHJlc2lkdWFscyhtb2RlbCwgdHlwZT0ncGVhcnNvbicpKSkgI3RyYW5zZm9ybWVkIHBlYXJzb24gcmVzaWR1YWxzCiAgcGxvdChmLHIsY29sPWNvbCwgbWFpbj0nU2NhbGUtTG9jYXRpb24gUGxvdCcpIAogIEwxIDwtIGxvZXNzKHJ+ZikKICBmdmVjID0gc2VxKG1pbihmKSxtYXgoZiksbGVuZ3RoLm91dD0xMDAwKQogIGxpbmVzKGZ2ZWMscHJlZGljdChMMSxmdmVjKSxjb2w9MikKfQpgYGAKCiMgTG9hZGluZyBpbiBkYXRhCgpgYGB7ciBMb2FkaW5nIGRhdGEsIGluY2x1ZGU9RkFMU0V9CkJpb0RhdEZ1bGwyIDwtIHJlYWQuY3N2KCJ+L1F1ZWVucy9DbGFzc2VzL1NlbWVzdGVyXzQvQmlvODEyX2Jpb2luZi9FbmRvcGh5dGVfcHJvamVjdC9FbmRvcGh5dGVfcHJvamVjdC9EYXRhL0Jpb0RhdEZ1bGwyLmNzdiIpCmNvbG5hbWVzKEJpb0RhdEZ1bGwyKVtjb2xuYW1lcyhCaW9EYXRGdWxsMik9PSJQbGFudCJdIDwtICJTcGVjaWVzIgoKbWFwcGluZ19maWxlIDwtIHJlYWQuY3N2KCJ+L1F1ZWVucy9DbGFzc2VzL1NlbWVzdGVyXzQvQmlvODEyX2Jpb2luZi9FbmRvcGh5dGVfcHJvamVjdC9FbmRvcGh5dGVfcHJvamVjdC9EYXRhL21hcHBpbmdfZmlsZS5jc3YiKQptYXBwaW5nX2ZpbGUkU2FtcGxlSUQ8LWFzLmNoYXJhY3RlcihtYXBwaW5nX2ZpbGUkU2FtcGxlSUQpCm1hcHBpbmdfZmlsZSRTcGVjaWVzPC1hcy5jaGFyYWN0ZXIobWFwcGluZ19maWxlJFNwZWNpZXMpCgptZXRhZ2Vub21lX3ByZWRpY3Rpb25zIDwtIHJlYWQuZGVsaW0oIn4vUXVlZW5zL0NsYXNzZXMvU2VtZXN0ZXJfNC9CaW84MTJfYmlvaW5mL0VuZG9waHl0ZV9wcm9qZWN0L0VuZG9waHl0ZV9wcm9qZWN0L0RhdGEvbWV0YWdlbm9tZV9wcmVkaWN0aW9ucy50eHQiKQpoZWFkKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMpCgpueSA8LSBhcy5jaGFyYWN0ZXIobWV0YWdlbm9tZV9wcmVkaWN0aW9ucyRLRUdHX0Rlc2NyaXB0aW9uKQpPVFU8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnMkT1RVLklECm1ldGFnZW5vbWVfcHJlZGljdGlvbnM8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnNbLGMoLTEsLWxlbmd0aChtZXRhZ2Vub21lX3ByZWRpY3Rpb25zKSldClNhbXBsZXMgPC0gY29sbmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucykKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczwtZGF0YS5mcmFtZSh0KG1ldGFnZW5vbWVfcHJlZGljdGlvbnMpKQpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zKSA8LSBueQoKT1RVX3RhYmxlX1ExIDwtIHJlYWQuZGVsaW0oIn4vUXVlZW5zL0NsYXNzZXMvU2VtZXN0ZXJfNC9CaW84MTJfYmlvaW5mL0VuZG9waHl0ZV9wcm9qZWN0L0VuZG9waHl0ZV9wcm9qZWN0L0RhdGEvOTdfT1RVX3RhYmxlX1FJSU1FMS50eHQiLCBoZWFkZXI9VCkKaGVhZChPVFVfdGFibGVfUTEpClg8LU9UVV90YWJsZV9RMVssYygxLGxlbmd0aChPVFVfdGFibGVfUTEpKV0KCk9UVV90YWJsZTwtcmVhZC5kZWxpbSgifi9RdWVlbnMvQ2xhc3Nlcy9TZW1lc3Rlcl80L0JpbzgxMl9iaW9pbmYvRW5kb3BoeXRlX3Byb2plY3QvRW5kb3BoeXRlX3Byb2plY3QvRGF0YS85N19PVFUudHh0IikKaGVhZChPVFVfdGFibGUpCmNvbG5hbWVzKE9UVV90YWJsZSlbY29sbmFtZXMoT1RVX3RhYmxlKT09Ik9UVS5JRCJdIDwtICJPVFVfSUQiCk9UVV90YWJsZTwtbWVyZ2UoT1RVX3RhYmxlLFgsIGJ5PSJPVFVfSUQiKQpPVFVfdGFibGUkdGF4b25vbXkueDwtTlVMTApjb2xuYW1lcyhPVFVfdGFibGUpW2NvbG5hbWVzKE9UVV90YWJsZSk9PSJ0YXhvbm9teS55Il0gPC0gInRheG9ub215IgoKZGlzdF9tYXRyaXggPC0gcmVhZC5jc3YoIn4vUXVlZW5zL0NsYXNzZXMvU2VtZXN0ZXJfNC9CaW84MTJfYmlvaW5mL0VuZG9waHl0ZV9wcm9qZWN0L0VuZG9waHl0ZV9wcm9qZWN0L0RhdGEvZGlzdF9tYXRyaXhfc2FtcGxlcy5jc3YiLCByb3cubmFtZXM9MSkKYGBgCgojIE9UVQojIyBBTkFMWVNJUwojIyMgT1RVIGRpdmVyc2l0eSBhbmQgc3VjaApgYGB7cn0KT1RVX3RhYmxlLnQ8LXRyYW5zcG9zZS5PVFUoT1RVX3RhYmxlKQphYjwtdGFibGUodW5saXN0KE9UVV90YWJsZS50KSkKYWJbMToyMF0gCgpiYXJwbG90KGxvZyhhYiksIGxhcz0xLCB4bGFiID0gIkFidW5kYW5kIGluIG1hdHJpeCIsIAogICAgICAgIHlsYWIgPSAibG9nIChmcmVxdWVuY3kpIiwgCiAgICAgICAgeWxpbSA9IGMoMCwgbWF4KGxvZyhhYikpKzIpKQoKCnJvdy5uYW1lcyhPVFVfdGFibGUpPC1PVFVfdGFibGUkT1RVX0lECk9UVV90YWJsZS5PVFVfSUQ8LU9UVV90YWJsZSRPVFVfSUQKT1RVX3RhYmxlJE9UVV9JRDwtTlVMTApPVFVfdGFibGU8LU9UVV90YWJsZVssY29sU3VtcyhPVFVfdGFibGVbLGMoMToobGVuZ3RoKGNvbG5hbWVzKE9UVV90YWJsZSkpLTEpKV0pIT0wXQpPVFVfdGFibGUudDwtdHJhbnNwb3NlLk9UVShPVFVfdGFibGUpCgoKT1RVX3RhYmxlLm5zPC1PVFVfdGFibGVbcm93U3VtcyhPVFVfdGFibGVbLGMoMToobGVuZ3RoKE9UVV90YWJsZSktMSkpXSkhPTEsXQpkaW0oT1RVX3RhYmxlKQpkaW0oT1RVX3RhYmxlLm5zKQoKCk9UVV90YWJsZTwtT1RVX3RhYmxlLm5zCk9UVV90YWJsZS50PC10cmFuc3Bvc2UuT1RVKE9UVV90YWJsZSkKCiMgU2VwZXJhdGUgdGF4b25vbXkKT1RVX3RhYmxlJHRheG9ub215PC1hcy5jaGFyYWN0ZXIoT1RVX3RhYmxlJHRheG9ub215KQoKdGF4LmNsYXNzZXMgPC0gYygia2luZ2RvbSIsICJwaHlsdW0iLCAiY2xhc3MiLCAib3JkZXIiLCAiZmFtaWx5IiwgImdlbnVzIiwgInNwZWNpZXMiKQpPVFVfdGFibGUudGF4IDwtIGNvbC5zcGxpdHVwKE9UVV90YWJsZSwgY29sPSJ0YXhvbm9teSIsIHNlcD0iOyAiLGRyb3A9VFJVRSwgbmFtZXM9dGF4LmNsYXNzZXMpCk9UVV90YWJsZS50YXgkdGF4b25vbXk8LU9UVV90YWJsZSR0YXhvbm9teQoKYGBgCgojIyMgTWFraW5nIHRoZSBtZXRhZGF0YQpgYGB7cn0KU2FtcGxlczwtY29sbmFtZXMoT1RVX3RhYmxlKQoKT1RVLmluZm88LWRhdGEuZnJhbWUoU2FtcGxlSUQ9U2FtcGxlcywgQWxwaGEuZGl2PXJlcChOQSwgbGVuZ3RoKFNhbXBsZXMpKSxTcGVjaWVzPXJlcChOQSwgbGVuZ3RoKFNhbXBsZXMpKSkKT1RVLmluZm8kU2FtcGxlSUQ8LWFzLmNoYXJhY3RlcihPVFUuaW5mbyRTYW1wbGVJRCkKCmZvcihpIGluIDE6KGxlbmd0aChTYW1wbGVzKS0xKSl7Ck9UVS5pbmZvJFNhbXBsZUlEW2ldPC1TYW1wbGVzW2ldCk9UVS5pbmZvJEFscGhhLmRpdltpXTwtZGl2ZXJzaXR5KE9UVV90YWJsZS50W3Jvd25hbWVzKE9UVV90YWJsZS50KT09U2FtcGxlc1tpXSxdLCBpbmRleCA9ICJzaGFubm9uIiwgTUFSR0lOID0gMSwgYmFzZSA9IGV4cCgxKSkKT1RVLmluZm8kU3BlY2llc1tpXTwtbWFwcGluZ19maWxlW21hcHBpbmdfZmlsZSRTYW1wbGVJRD09U2FtcGxlc1tpXSxdJFNwZWNpZXMKfQoKT1RVLmluZm88LSBPVFUuaW5mb1stbnJvdyhPVFUuaW5mbyksXQpPVFUuaW5mbyRTcGVjaWVzPC1hcy5mYWN0b3IoT1RVLmluZm8kU3BlY2llcykgCmRldGFjaChwYWNrYWdlOnBseXIpCk9UVS5pbmZvICU+JSBncm91cF9ieShTcGVjaWVzKSAlPiUgc3VtbWFyaXNlKG1lYW4uQWxwaGEuZGl2PW1lYW4oQWxwaGEuZGl2KSkgLT4gT1RVLmluZm8yCk9UVS5pbmZvMjwtbWVyZ2UoT1RVLmluZm8yLCBCaW9EYXRGdWxsMiwgYnk9IlNwZWNpZXMiKQpPVFUuaW5mbzIkU3BlY2llczwtYXMuZmFjdG9yKE9UVS5pbmZvMiRTcGVjaWVzKQpPVFUuaW5mbyRTcGVjaWVzPC1hcy5mYWN0b3IoT1RVLmluZm8kU3BlY2llcykKCmBgYAoKIyMjIERpdmVyc2l0eSBNb2RlbApgYGB7ciBSaWNobmVzcyBtb2RlbH0KIyBOb3JtYWw/CmNvbG5hbWVzKE9UVS5pbmZvMikKY29sbmFtZXMoT1RVLmluZm8yKVtjb2xuYW1lcyhPVFUuaW5mbzIpPT0iQW5udWFsLm1lYW4udGVtcGVyYXR1cmUuLi5DLiJdIDwtICJBbm51YWxNZWFuVGVtcGVyYXR1cmUiCmNvbG5hbWVzKE9UVS5pbmZvMilbY29sbmFtZXMoT1RVLmluZm8yKT09Ik1lYW4uZGl1cm5hbC50ZW1wZXJhdHVyZS5yYW5nZS4ubWVhbi5wZXJpb2QubWF4Lm1pbi4uLi4uQy4iXSA8LSAiTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlIgpjb2xuYW1lcyhPVFUuaW5mbzIpW2NvbG5hbWVzKE9UVS5pbmZvMik9PSJUZW1wZXJhdHVyZS5zZWFzb25hbGl0eS4uQy5vZi5WLiJdIDwtICJUZW1wZXJhdHVyZVNlYXNvbmFsaXR5Igpjb2xuYW1lcyhPVFUuaW5mbzIpW2NvbG5hbWVzKE9UVS5pbmZvMik9PSJNYXgudGVtcGVyYXR1cmUub2Yud2FybWVzdC53ZWVrLi4uQy4iXSA8LSAiTWF4VGVtcGVyYXR1cmUiCmNvbG5hbWVzKE9UVS5pbmZvMilbY29sbmFtZXMoT1RVLmluZm8yKT09Ik1pbi50ZW1wZXJhdHVyZS5vZi5jb2xkZXN0LndlZWsuLi5DLiJdIDwtICJNaW5UZW1wZXJhdHVyZSIKY29sbmFtZXMoT1RVLmluZm8yKVtjb2xuYW1lcyhPVFUuaW5mbzIpPT0iQW5udWFsLnByZWNpcGl0YXRpb24uLm1tLiJdIDwtICJBbm51YWxQcmVjaXBpdGF0aW9uIgpjb2xuYW1lcyhPVFUuaW5mbzIpW2NvbG5hbWVzKE9UVS5pbmZvMik9PSJQcmVjaXBpdGF0aW9uLm9mLndldHRlc3Qud2Vlay4ubW0uIl0gPC0gIk1heFByZWNpcGl0YXRpb24iCmNvbG5hbWVzKE9UVS5pbmZvMilbY29sbmFtZXMoT1RVLmluZm8yKT09IlByZWNpcGl0YXRpb24ub2YuZHJpZXN0LnF1YXJ0ZXIuLm1tLiJdIDwtICJNaW5QcmVjaXBpdGF0aW9uIgpjb2xuYW1lcyhPVFUuaW5mbzIpW2NvbG5hbWVzKE9UVS5pbmZvMik9PSJQcmVjaXBpdGF0aW9uLm9mLmNvbGRlc3QucXVhcnRlci4ubW0uIl0gPC0gIkNvbGRlc3RQcmVjaXBpdGF0aW9uIgpjb2xuYW1lcyhPVFUuaW5mbzIpW2NvbG5hbWVzKE9UVS5pbmZvMik9PSJQcmVjaXBpdGF0aW9uLnNlYXNvbmFsaXR5Li5DLm9mLlYuIl0gPC0gIlByZWNpcGl0YXRpb25TZWFzb25hbGl0eSIKCgpNeWRhdGE8LU9UVS5pbmZvMlssYygxOjYsODoxMCwxNjoxNywxOSwyMSwyMyldClk8LU15ZGF0YVssYyg4Omxlbmd0aChNeWRhdGEpKV0KY292YXJfY29yID0gY29yKFkpCmNvcnJwbG90Lm1peGVkKGNvdmFyX2NvciwgdXBwZXIgPSAiZWxsaXBzZSIsIGxvd2VyID0gIm51bWJlciIpCk15ZGF0YV9QQ0EgPSBkdWRpLnBjYShkZiA9IFksIHNjYW5uZiA9IEZBTFNFLCBuZiA9IDIsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkKTXlkYXRhX1BDQSRjbwpzLmNvcmNpcmNsZShNeWRhdGFfUENBJGNvKQpNeWRhdGFfUENBJGVpZy9zdW0oTXlkYXRhX1BDQSRlaWcpCmNvbG5hbWVzKE15ZGF0YSkKCk15ZGF0YSRMYXQgPC0gc2NhbGUoTXlkYXRhJExhdCkKTXlkYXRhJExvbmcgPC0gc2NhbGUoTXlkYXRhJExvbmcpCk15ZGF0YSRBbm51YWxQcmVjaXBpdGF0aW9uIDwtIHNjYWxlKE15ZGF0YSRBbm51YWxQcmVjaXBpdGF0aW9uKQpNeWRhdGEkQW5udWFsTWVhblRlbXBlcmF0dXJlIDwtIHNjYWxlKE15ZGF0YSRBbm51YWxNZWFuVGVtcGVyYXR1cmUpCk15ZGF0YSRQcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHkgPC0gc2NhbGUoTXlkYXRhJFByZWNpcGl0YXRpb25TZWFzb25hbGl0eSkKTXlkYXRhJFRlbXBlcmF0dXJlU2Vhc29uYWxpdHkgIDwtIHNjYWxlKE15ZGF0YSRUZW1wZXJhdHVyZVNlYXNvbmFsaXR5KQpNeWRhdGEkTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlPC0gc2NhbGUoTXlkYXRhJE1lYW5EaXVybmFsVGVtcGVyYXR1cmVSYW5nZSkKTXlkYXRhJE1pblRlbXBlcmF0dXJlIDwtIHNjYWxlKE15ZGF0YSRNaW5UZW1wZXJhdHVyZSkKTXlkYXRhJE1heFRlbXBlcmF0dXJlIDwtIHNjYWxlKE15ZGF0YSRNYXhUZW1wZXJhdHVyZSkKCgoKbW9kMTwtbG0obWVhbi5BbHBoYS5kaXYgfiBMYXQgKyBMb25nICsgQW5udWFsUHJlY2lwaXRhdGlvbiArIEFubnVhbE1lYW5UZW1wZXJhdHVyZSArIFByZWNpcGl0YXRpb25TZWFzb25hbGl0eSArIFRlbXBlcmF0dXJlU2Vhc29uYWxpdHkgICsgTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlKyBNaW5UZW1wZXJhdHVyZSArIE1heFRlbXBlcmF0dXJlICwgZGF0YSA9IE15ZGF0YSkKCmNhcjo6cXFwKE9UVS5pbmZvMiRtZWFuLkFscGhhLmRpdiwgIm5vcm0iKQpwbG90KGRlbnNpdHkoT1RVLmluZm8yJG1lYW4uQWxwaGEuZGl2KSkKc2hhcGlyby50ZXN0KE9UVS5pbmZvMiRtZWFuLkFscGhhLmRpdikKYnB0ZXN0KG1vZDEpCnBsb3QobW9kMSkKCiMgSXMgZW5kb3BoeXRlIGRpdmVyc2l0eSBkcml2ZW4gYnkgYW55IGNsaW1hdGljIGRhdGE/IE5PCm1vZDEubUxhdDwtdXBkYXRlKG1vZDEsLn4uIC0gTGF0KQphbm92YShtb2QxLG1vZDEubUxhdCkKCm1vZDEubUxvbmc8LXVwZGF0ZShtb2QxLm1MYXQsLn4uIC0gTG9uZykKYW5vdmEobW9kMS5tTGF0LG1vZDEubUxvbmcpCgptb2QxLm1Bbm51YWxQcmVjaXBpdGF0aW9uPC11cGRhdGUobW9kMS5tTG9uZywufi4gLSBBbm51YWxQcmVjaXBpdGF0aW9uKQphbm92YShtb2QxLm1Mb25nLG1vZDEubUFubnVhbFByZWNpcGl0YXRpb24pCgptb2QxLm1Bbm51YWxNZWFuVGVtcGVyYXR1cmU8LXVwZGF0ZShtb2QxLm1Bbm51YWxQcmVjaXBpdGF0aW9uLC5+LiAtIEFubnVhbE1lYW5UZW1wZXJhdHVyZSkKYW5vdmEobW9kMS5tQW5udWFsUHJlY2lwaXRhdGlvbixtb2QxLm1Bbm51YWxNZWFuVGVtcGVyYXR1cmUpCgptb2QxLm1QcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHk8LXVwZGF0ZShtb2QxLm1Bbm51YWxNZWFuVGVtcGVyYXR1cmUsLn4uIC0gUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5KQphbm92YShtb2QxLm1Bbm51YWxNZWFuVGVtcGVyYXR1cmUsIG1vZDEubVByZWNpcGl0YXRpb25TZWFzb25hbGl0eSkKCm1vZDEubVRlbXBlcmF0dXJlU2Vhc29uYWxpdHk8LXVwZGF0ZShtb2QxLm1QcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHksLn4uIC0gVGVtcGVyYXR1cmVTZWFzb25hbGl0eSkKYW5vdmEobW9kMS5tUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5LG1vZDEubVRlbXBlcmF0dXJlU2Vhc29uYWxpdHkpCgptb2QxLm1NZWFuRGl1cm5hbFRlbXBlcmF0dXJlUmFuZ2U8LXVwZGF0ZShtb2QxLm1UZW1wZXJhdHVyZVNlYXNvbmFsaXR5LC5+LiAtIE1lYW5EaXVybmFsVGVtcGVyYXR1cmVSYW5nZSkKYW5vdmEobW9kMS5tVGVtcGVyYXR1cmVTZWFzb25hbGl0eSwgbW9kMS5tTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlKQoKIyBNaW4gdGVtcGVyYXR1cmUgaXMgYSBzaWduaWZpY2FudCBwcmVkaWN0b3IhCm1vZDEubU1pblRlbXBlcmF0dXJlPC11cGRhdGUobW9kMS5tTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlLC5+LiAtIE1pblRlbXBlcmF0dXJlKQphbm92YShtb2QxLm1NZWFuRGl1cm5hbFRlbXBlcmF0dXJlUmFuZ2UsIG1vZDEubU1pblRlbXBlcmF0dXJlKQoKIyBNYXggdGVtcGVyYXR1cmUgaXMgYSBzaWduaWZpY2FudCBwcmVkaWN0b3IhCm1vZDEubU1heFRlbXBlcmF0dXJlPC11cGRhdGUobW9kMS5tTWluVGVtcGVyYXR1cmUsLn4uIC0gTWF4VGVtcGVyYXR1cmUpCmFub3ZhKG1vZDEubU1pblRlbXBlcmF0dXJlLCBtb2QxLm1NYXhUZW1wZXJhdHVyZSkKCgptb2QyPC0gbG0oQWxwaGEuZGl2flNwZWNpZXMsZGF0YT1PVFUuaW5mbykKc3VtbWFyeShtb2QyKQpgYGAKIyMjIENvbXBvc2l0aW9uIG1vZGVsCmBgYHtyIG11bHRpdmFyaWF0ZSBtb2RlbH0KClg8LU9UVS5pbmZvWyxjKDEsMyldCk9UVV90YWJsZS50JFNhbXBsZUlEPC1yb3cubmFtZXMoT1RVX3RhYmxlLnQpCk9UVV90YWJsZS50MTwtbWVyZ2UoT1RVX3RhYmxlLnQsWCwgYnk9IlNhbXBsZUlEIikKCk9UVV90YWJsZS50MTwtYWdncmVnYXRlKE9UVV90YWJsZS50MSwgYnkgPSBsaXN0KHNwZWNpZXM9T1RVX3RhYmxlLnQxJFNwZWNpZXMpLCBGVU49bWVhbikKT1RVX3RhYmxlLnQxJFNhbXBsZUlEPC1OVUxMCgpyb3cubmFtZXMoT1RVX3RhYmxlLnQxKTwtT1RVX3RhYmxlLnQxJHNwZWNpZXMKT1RVX3RhYmxlLnQxJHNwZWNpZXM8LU5VTEwKT1RVX3RhYmxlLnQxJFNwZWNpZXM8LU5VTEwKc3VtKGlzLm5hKE9UVV90YWJsZS50MSkpCgpPVFVfdGFibGUudG1hdGNoZWQ8LU9UVV90YWJsZS50MVttYXRjaChyb3duYW1lcyhkaXN0X21hdHJpeCksIHJvd25hbWVzKE9UVV90YWJsZS50MSkpLCBdCmJldGFfZGl2TWF0PC0gdmVnZGlzdChPVFVfdGFibGUudG1hdGNoZWQsICJicmF5IixkaWFnPVQpCgoKIyBBcmUgdGhlIGVuZG9waHl0ZXMgbW9yZSBzaW1pbGFyIGluIHNwZWNpZXMgdGhhdCBhcmUgbW9yZSBjbG9zZWx5IHJlbGF0ZWQgcGh5bG9nZW5pY2FsbHk/IE5PISAKbWFudGVsKGJldGFfZGl2TWF0LGRpc3RfbWF0cml4KQoKIyBhcmUgc2ltaWxhcml0eSBpbiB0aGUgZW5kb3BoeXRlIGNvbXBvc2l0aW9uIGRyaXZlbiBieSBjbGltYXRlIGRhdGE/CgoKTXlkYXRhJFNwZWNpZXM8LXBseXI6OnJldmFsdWUoTXlkYXRhJFNwZWNpZXMsIGMoIkJyYXNzaWNhX25hcHVzIj0iQnJhc3NpY2EgbmFwdXMiLCAiQnJhc3NpY2Ffb2xlcmFjZWEiPSJCcmFzc2ljYSBvbGVyYWNlYSIsIkNyYXRvbmV1cm9uIj0iQ3JhdG9uZXVyb24gZmlsaWNpbnVtIiwiR3JpbW1pYSI9IkdyaW1taWEgcGlsaWZlcmEiLCJNaWNyb2Rlc21pcyI9Ik1pY3JvZGVzbWlzIGNhc2VhcmlpZm9saWEiLCJPcmNoaWQiPSJQaGFsYWVub3BzaXMiLCJPcnl6YSI9Ik9yeXphIHNhdGl2YSIsIlBhZW9uaWFfcm9ja2lpIj0iUGFlb25pYSByb2NraWkiLCJQYWVvbmlhX3N1ZmZydXRpY29zYSI9IlBhZW9uaWEgc3VmZnJ1dGljb3NhIiwiUGludXMiPSJQaW51cyBwaW5hc3RlciIsIlBpbnVzX2ZsZXhpbGlzIj0iUGludXMgZmxleGlsaXMiLCJQeWxhaXNpZWxsYSI9IlB5bGFpc2lhIHBvbHlhbnRoYSIsIlJvdGhtYW5uaWEiPSJSb3RobWFubmlhIG1hY3JvcGh5bGxhIiwiU2FudGlyaWEiPSJTYW50aXJpYSBhcGljdWxhdGEiLCJTb2xhbnVtIj0iU29sYW51bSBseWNvcGVyc2ljdW0iLCJWaXRpcyI9IlZpdGlzIHZpbmlmZXJhIiwiWmVhIj0iWmVhIG1heXMiKSkKcm93bmFtZXMoTXlkYXRhKTwtTXlkYXRhJFNwZWNpZXMKCgpPVFVfdGFibGUudDEkc3BlY2llczwtcm93bmFtZXMoT1RVX3RhYmxlLnQxKQpPVFVfdGFibGUudDEkc3BlY2llczwtYXMuZmFjdG9yKE9UVV90YWJsZS50MSRzcGVjaWVzKQpPVFVfdGFibGUudDEkc3BlY2llczwtcGx5cjo6cmV2YWx1ZShPVFVfdGFibGUudDEkc3BlY2llcywgYygiQnJhc3NpY2FfbmFwdXMiPSJCcmFzc2ljYSBuYXB1cyIsICJCcmFzc2ljYV9vbGVyYWNlYSI9IkJyYXNzaWNhIG9sZXJhY2VhIiwiQ3JhdG9uZXVyb24iPSJDcmF0b25ldXJvbiBmaWxpY2ludW0iLCJHcmltbWlhIj0iR3JpbW1pYSBwaWxpZmVyYSIsIk1pY3JvZGVzbWlzIj0iTWljcm9kZXNtaXMgY2FzZWFyaWlmb2xpYSIsIk9yY2hpZCI9IlBoYWxhZW5vcHNpcyIsIk9yeXphIj0iT3J5emEgc2F0aXZhIiwiUGFlb25pYV9yb2NraWkiPSJQYWVvbmlhIHJvY2tpaSIsIlBhZW9uaWFfc3VmZnJ1dGljb3NhIj0iUGFlb25pYSBzdWZmcnV0aWNvc2EiLCJQaW51cyI9IlBpbnVzIHBpbmFzdGVyIiwiUGludXNfZmxleGlsaXMiPSJQaW51cyBmbGV4aWxpcyIsIlB5bGFpc2llbGxhIj0iUHlsYWlzaWEgcG9seWFudGhhIiwiUm90aG1hbm5pYSI9IlJvdGhtYW5uaWEgbWFjcm9waHlsbGEiLCJTYW50aXJpYSI9IlNhbnRpcmlhIGFwaWN1bGF0YSIsIlNvbGFudW0iPSJTb2xhbnVtIGx5Y29wZXJzaWN1bSIsIlZpdGlzIj0iVml0aXMgdmluaWZlcmEiLCJaZWEiPSJaZWEgbWF5cyIpKQpyb3duYW1lcyhPVFVfdGFibGUudDEpPC1PVFVfdGFibGUudDEkc3BlY2llcwpPVFVfdGFibGUudDEkc3BlY2llczwtTlVMTAoKCk9UVV90YWJsZS50MS5oZWxsIDwtIGRlY29zdGFuZChPVFVfdGFibGUudDEsICJoZWxsIikKCgpNeWRhdGE8LU15ZGF0YVttYXRjaChyb3duYW1lcyhPVFVfdGFibGUudDEpLCByb3duYW1lcyhNeWRhdGEpKSwgXQp2YXIgPC1NeWRhdGFbLGMoMzoxNildCgpmb3JtdWxhUkRBPC0gcmRhKE9UVV90YWJsZS50MS5oZWxsIH4gTGF0ICsgTG9uZyArIEFubnVhbFByZWNpcGl0YXRpb24gKyBBbm51YWxNZWFuVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHkgKyBUZW1wZXJhdHVyZVNlYXNvbmFsaXR5ICsgTWluVGVtcGVyYXR1cmUgKyBNYXhUZW1wZXJhdHVyZSArIE1lYW5EaXVybmFsVGVtcGVyYXR1cmVSYW5nZSsgTWluUHJlY2lwaXRhdGlvbisgTWF4UHJlY2lwaXRhdGlvbiArIENvbGRlc3RQcmVjaXBpdGF0aW9uLCBkYXRhPXZhciwgc2NhbGU9RikKCmhlYWQoc3VtbWFyeShmb3JtdWxhUkRBKSkKUnNxdWFyZUFkaihmb3JtdWxhUkRBKQphbm92YShmb3JtdWxhUkRBLCBwZXJtdXRhdGlvbnM9MTAwMCkKYW5vdmFNQVJHSU48LWFub3ZhLmNjYShmb3JtdWxhUkRBLCBieT0ibWFyZ2luIiwgcGVybXV0YXRpb25zPTEwMDApCgp2YXJwYXJ0KE9UVV90YWJsZS50MS5oZWxsLCB+TGF0ICsgTG9uZywgfiBBbm51YWxNZWFuVGVtcGVyYXR1cmUgKyBNZWFuRGl1cm5hbFRlbXBlcmF0dXJlUmFuZ2UgKyBUZW1wZXJhdHVyZVNlYXNvbmFsaXR5ICsgTWF4VGVtcGVyYXR1cmUgKyBNaW5UZW1wZXJhdHVyZSwgfiBBbm51YWxQcmVjaXBpdGF0aW9uICsgUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5ICsgTWF4UHJlY2lwaXRhdGlvbisgTWluUHJlY2lwaXRhdGlvbiArIENvbGRlc3RQcmVjaXBpdGF0aW9uLCBkYXRhPXZhcikKYGBgCgojIyBGSUdVUkVTCgpgYGB7cn0KT1RVLmluZm8kU3BlY2llczwtcGx5cjo6cmV2YWx1ZShPVFUuaW5mbyRTcGVjaWVzLCBjKCJCcmFzc2ljYV9uYXB1cyI9IkJyYXNzaWNhIG5hcHVzIiwgIkJyYXNzaWNhX29sZXJhY2VhIj0iQnJhc3NpY2Egb2xlcmFjZWEiLCJDcmF0b25ldXJvbiI9IkNyYXRvbmV1cm9uIGZpbGljaW51bSIsIkdyaW1taWEiPSJHcmltbWlhIHBpbGlmZXJhIiwiTWljcm9kZXNtaXMiPSJNaWNyb2Rlc21pcyBjYXNlYXJpaWZvbGlhIiwiT3JjaGlkIj0iUGhhbGFlbm9wc2lzIiwiT3J5emEiPSJPcnl6YSBzYXRpdmEiLCJQYWVvbmlhX3JvY2tpaSI9IlBhZW9uaWEgcm9ja2lpIiwiUGFlb25pYV9zdWZmcnV0aWNvc2EiPSJQYWVvbmlhIHN1ZmZydXRpY29zYSIsIlBpbnVzIj0iUGludXMgcGluYXN0ZXIiLCJQaW51c19mbGV4aWxpcyI9IlBpbnVzIGZsZXhpbGlzIiwiUHlsYWlzaWVsbGEiPSJQeWxhaXNpYSBwb2x5YW50aGEiLCJSb3RobWFubmlhIj0iUm90aG1hbm5pYSBtYWNyb3BoeWxsYSIsIlNhbnRpcmlhIj0iU2FudGlyaWEgYXBpY3VsYXRhIiwiU29sYW51bSI9IlNvbGFudW0gbHljb3BlcnNpY3VtIiwiVml0aXMiPSJWaXRpcyB2aW5pZmVyYSIsIlplYSI9IlplYSBtYXlzIikpCgoKIyBBbHBoYSB0byBzZWNpZXMKQWRpdl9zcGVjaWVzX09UVTwtZ2dwbG90KE9UVS5pbmZvLCBhZXMoeT1BbHBoYS5kaXYseD1TcGVjaWVzKSkrCiAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvcj1TcGVjaWVzKSkrCiAgbGFicyh5PSJTaGFubm9uIGRpdmVyc2l0eSIpKwogIHRoZW1lX2thdGhlcmluZSgpKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKwogIGdndGl0bGUoIkFscGhhIERpdmVyc2l0eSBvZiBPVFVzIGJ5IFNwZWNpZXMiKQpnZ3NhdmUoIkFkaXZfc3BlY2llcy5PVFVfUExPVC5wZGYiLEFkaXZfc3BlY2llc19PVFUpCgojIFJEQQpzbXJ5IDwtIHN1bW1hcnkoZm9ybXVsYVJEQSkKZGYxICA8LSBkYXRhLmZyYW1lKHNtcnkkc2l0ZXNbLDE6Ml0pICAgICAgICMgUEMxIGFuZCBQQzIKZGYyICA8LSBkYXRhLmZyYW1lKHNtcnkkYmlwbG90WywxOjJdKSAgICAgIyBsb2FkaW5ncyBmb3IgUEMxIGFuZCBQQzIKcmRhLnBsb3QgPC0gZ2dwbG90KGRmMSwgYWVzKHg9UkRBMSwgeT1SREEyKSkgKyAKICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvd25hbWVzKGRmMSkpLHNpemU9Myxwb3NpdGlvbj1wb3NpdGlvbl9qaXR0ZXIod2lkdGg9LjIsaGVpZ2h0PS4yKSkgKwogIGdlb21fcG9pbnQoYWVzKGFscGhhPTAuMykpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRvdHRlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRvdHRlZCIpICAKCm5hbWVzPC1jKCJMYXRpdHVkZSIsIkxvbmdpdHVkZSIsIlxuTWVhbiBBbm51YWwgVGVtcCIsICJEaXVybmFsIFRlbXAgUmFuZ2UiLCAiXG5UZW1wIFNlYXNvbmFsaXR5IiwgIk1heCBUZW1wXG4iLCAiTWluIFRlbXAiLCAiQW5udWFsIFByZWNpcGl0YXRpb25cbiIsICJNYXggUHJlY2lwaXRhdGlvbiIsICJQcmVjaXBpdGF0aW9uIFNlYXNvbmFsaXR5IiwgIk1pbiBQcmVjaXBpdGF0aW9uIiwgIkNvbGRlc3QgUHJlY2lwaXRhdGlvbiAgICAiKQpyb3duYW1lcyhkZjIpCihmb3JtdWxhUkRBLlBMT1Q8LXJkYS5wbG90ICsKICBnZW9tX3NlZ21lbnQoZGF0YT1kZjIsIGFlcyh4PTAsIHhlbmQ9UkRBMSwgeT0wLCB5ZW5kPVJEQTIpLCAKICAgICAgICAgICAgICAgY29sb3I9InJlZCIsIGFycm93PWFycm93KGxlbmd0aD11bml0KDAuMDEsIm5wYyIpKSkgKwogIGdlb21fdGV4dChkYXRhPWRmMiwgCiAgICAgICAgICAgIGFlcyh4PVJEQTEseT1SREEyLGxhYmVsPW5hbWVzLAogICAgICAgICAgICAgICAgaGp1c3Q9MC41KigxLXNpZ24oUkRBMSkpLHZqdXN0PTAuNSooMS1zaWduKFJEQTIpKSksIAogICAgICAgICAgICBjb2xvcj0icmVkIiwgc2l6ZT00KSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTAuOCwgMC44KSx4bGltID0gYygtMS4zLCAxLjMpKSArdGhlbWVfa2F0aGVyaW5lKCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKQpnZ3NhdmUoImZvcm11bGFSREEuT1RVX1BMT1QucGRmIixmb3JtdWxhUkRBLlBMT1QpCgojIE5NRFMKI01ha2UgYSBtYXRyaXggd2l0aCBubyByb3cgb3IgY29sdW1uIGVxdWFsIHRvIDAgKGRvIG5vdCBlbmNsdWRlIHRoZSBlbnYgdmFyaWFibGUgKEdNIENPVkVSQUdFKSkKT1RVX3RhYmxlLnQyPC1tZXJnZShPVFVfdGFibGUudCxYLCBieT0iU2FtcGxlSUQiKQpPVFVfdGFibGUudDIkU2FtcGxlSUQ8LU5VTEwKcm93bmFtZXMuTTwtT1RVX3RhYmxlLnQyJFNwZWNpZXMKT1RVX3RhYmxlLnQyJFNwZWNpZXM8LU5VTEwKTSA8LSBhcy5tYXRyaXgoT1RVX3RhYmxlLnQyKQpNW2lzLm5hKE0pXSA8LSAwCndoaWNoKCBjb2xTdW1zKE0pPT0wICkKd2hpY2goIHJvd1N1bXMoTSk9PTAgKQoKcm93bmFtZXMoTSkgPC0gcm93bmFtZXMuTQoKZGlzdF9NIDwtIHZlZ2Rpc3QoTSwgbWV0aG9kID0gImJyYXkiLCBiaW5hcnkgPSBUKQojVGhlIG1ldGFNRFMgYW5hbHlzaXMgY291bGQgaGF2ZSBkb25lIHRoZSBkaXN0YW5jZSBtYXRyaXggaW50ZXJuYWxseSBidXQgaSB3b3VsZCByYXRoZXIgY29udHJvbCBpdCBzaW5jZSBpIGhhdmUgcHJlc2VuY2UvYWJzY2VuY2UKbWV0YS5ubWRzIDwtIG1ldGFNRFMoZGlzdF9NLCBrPTIsIHRyeW1heCA9IDIwMDApCnN0cihtZXRhLm5tZHMpCnN0cmVzc3Bsb3QobWV0YS5ubWRzKQoKU3BlY2llczwtZGF0YS5mcmFtZShTcGVjaWVzPWFzLmZhY3Rvcihyb3duYW1lcy5NKSkKIyBlbnZmaXQKZW52Zml0IDwtIGVudmZpdChtZXRhLm5tZHMsIGVudiA9IFNwZWNpZXMsIHBlcm0gPSA5OTkpICNzdGFuZGFyZCBlbnZmaXQKZW52Zml0CgojZGF0YSBmb3IgcGxvdHRpbmcgCiMjTk1EUyBwb2ludHMKTk1EUy5kYXRhPC1TcGVjaWVzIApOTURTLmRhdGEkTk1EUzE8LW1ldGEubm1kcyRwb2ludHNbICwxXSAKTk1EUy5kYXRhJE5NRFMyPC1tZXRhLm5tZHMkcG9pbnRzWyAsMl0gCmNvbG5hbWVzKE5NRFMuZGF0YSlbMV0gPC0gIlNwZWNpZXMiCgptdWx0IDwtIDEgI211bHRpcGxpZXIgZm9yIHRoZSBhcnJvd3MgYW5kIHRleHQgZm9yIGVudmZpdCBiZWxvdy4gWW91IGNhbiBjaGFuZ2UgdGhpcyBhbmQgdGhlbiByZXJ1biB0aGUgcGxvdCBjb21tYW5kLgpsaWJyYXJ5KGdncGxvdDIpCihPVFUubm1kcy5nZzEgPC0gZ2dwbG90KGRhdGEgPSBOTURTLmRhdGEsIGFlcyh5ID0gTk1EUzIsIHggPSBOTURTMSkpKyAKICAgIGdlb21fcG9pbnQoIGFlcyhjb2xvciA9IE5NRFMuZGF0YSRTcGVjaWVzKSwgc2l6ZSA9IDEuNSxhbHBoYT0wLjYpKyAKICAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMC4yNSwwLjI1KSx5bGltID0gYygtMC4xLDAuMSkpICsgCiAgICB0aGVtZV9rYXRoZXJpbmUoKSkKZ2dzYXZlKCJubWRzLk9UVV9QTE9ULnBkZiIsT1RVLm5tZHMuZ2cxKQpgYGAKCgojIEZ1bmN0aW9ucwojIyBBTkFMWVNJUwojIyMgRnVuY3Rpb25hbCBkaXZlcnNpdHkgYW5kIHN1Y2gKYGBge3J9Cm1ldGFnZW5vbWVfcHJlZGljdGlvbnMKCm1ldGFnZW5vbWVfcHJlZGljdGlvbnM8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnNbLGNvbFN1bXMobWV0YWdlbm9tZV9wcmVkaWN0aW9uc1ssXSkhPTBdCm1ldGFnZW5vbWVfcHJlZGljdGlvbnM8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnNbcm93U3VtcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zWyxdKSE9MCxdCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMubnM8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnNbLGNvbFN1bXMobWV0YWdlbm9tZV9wcmVkaWN0aW9uc1ssXSkhPTFdCmRpbShtZXRhZ2Vub21lX3ByZWRpY3Rpb25zKQpkaW0obWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5ucykKCm1ldGFnZW5vbWVfcHJlZGljdGlvbnM8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnMubnMKCkZ1bmN0aW9uczwtY29sbmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucykKU2FtcGxlczwtcm93bmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucykKCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzwtZGF0YS5mcmFtZShTYW1wbGVJRD1TYW1wbGVzLCBPVFUuQWxwaGEuZGl2PXJlcChOQSwgbGVuZ3RoKFNhbXBsZXMpKSxTcGVjaWVzPXJlcChOQSwgbGVuZ3RoKFNhbXBsZXMpKSwgRnVuY3Rpb24uQWxwaGEuZGl2PXJlcChOQSwgbGVuZ3RoKFNhbXBsZXMpKSkKCndoaWNoKHNhcHBseShPVFVfdGFibGUudCwgaXMuY2hhcmFjdGVyKSkKT1RVX3RhYmxlLnQkU2FtcGxlSUQ8LU5VTEwKZm9yKGkgaW4gMToobGVuZ3RoKFNhbXBsZXMpKSl7Cm1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbyRTYW1wbGVJRFtpXTwtU2FtcGxlc1tpXQptZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8kT1RVLkFscGhhLmRpdltpXTwtZGl2ZXJzaXR5KE9UVV90YWJsZS50W3Jvd25hbWVzKE9UVV90YWJsZS50KT09U2FtcGxlc1tpXSxdLCBpbmRleCA9ICJzaGFubm9uIiwgTUFSR0lOID0gMSwgYmFzZSA9IGV4cCgxKSkKbWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvJEZ1bmN0aW9uLkFscGhhLmRpdltpXTwtZGl2ZXJzaXR5KG1ldGFnZW5vbWVfcHJlZGljdGlvbnNbcm93bmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucyk9PVNhbXBsZXNbaV0sXSwgaW5kZXggPSAic2hhbm5vbiIsIE1BUkdJTiA9IDEsIGJhc2UgPSBleHAoMSkpCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbyRTcGVjaWVzW2ldPC1tYXBwaW5nX2ZpbGVbbWFwcGluZ19maWxlJFNhbXBsZUlEPT1TYW1wbGVzW2ldLF0kU3BlY2llcwp9CgoKbWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvJFNwZWNpZXM8LWFzLmZhY3RvcihtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8kU3BlY2llcykKCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbyAlPiUgZHBseXI6Omdyb3VwX2J5KFNwZWNpZXMpICU+JSBzdW1tYXJpc2UobWVhbi5PVFUuQWxwaGEuZGl2PW1lYW4oT1RVLkFscGhhLmRpdiksbWVhbi5GdW5jdGlvbi5BbHBoYS5kaXY9bWVhbihGdW5jdGlvbi5BbHBoYS5kaXYpKSAtPiBtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzI8LW1lcmdlKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIsIEJpb0RhdEZ1bGwyLCBieT0iU3BlY2llcyIpCgpgYGAKCiMjIyBGdW5jdGlvbmFsIGRpdmVyc2l0eSBtb2RlbApgYGB7ciBSaWNobmVzcyBtb2RlbCBGVU59CiMgTm9ybWFsPwpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKVtjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKT09IkFubnVhbC5tZWFuLnRlbXBlcmF0dXJlLi4uQy4iXSA8LSAiQW5udWFsTWVhblRlbXBlcmF0dXJlIgpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKVtjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKT09Ik1lYW4uZGl1cm5hbC50ZW1wZXJhdHVyZS5yYW5nZS4ubWVhbi5wZXJpb2QubWF4Lm1pbi4uLi4uQy4iXSA8LSAiTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlIgpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKVtjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKT09IlRlbXBlcmF0dXJlLnNlYXNvbmFsaXR5Li5DLm9mLlYuIl0gPC0gIlRlbXBlcmF0dXJlU2Vhc29uYWxpdHkiCmNvbG5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIpW2NvbG5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIpPT0iTWF4LnRlbXBlcmF0dXJlLm9mLndhcm1lc3Qud2Vlay4uLkMuIl0gPC0gIk1heFRlbXBlcmF0dXJlIgpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKVtjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKT09Ik1pbi50ZW1wZXJhdHVyZS5vZi5jb2xkZXN0LndlZWsuLi5DLiJdIDwtICJNaW5UZW1wZXJhdHVyZSIKY29sbmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvMilbY29sbmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvMik9PSJBbm51YWwucHJlY2lwaXRhdGlvbi4ubW0uIl0gPC0gIkFubnVhbFByZWNpcGl0YXRpb24iCmNvbG5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIpW2NvbG5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIpPT0iUHJlY2lwaXRhdGlvbi5vZi53ZXR0ZXN0LndlZWsuLm1tLiJdIDwtICJNYXhQcmVjaXBpdGF0aW9uIgpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKVtjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKT09IlByZWNpcGl0YXRpb24ub2YuZHJpZXN0LnF1YXJ0ZXIuLm1tLiJdIDwtICJNaW5QcmVjaXBpdGF0aW9uIgpjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKVtjb2xuYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yKT09IlByZWNpcGl0YXRpb24ub2YuY29sZGVzdC5xdWFydGVyLi5tbS4iXSA8LSAiQ29sZGVzdFByZWNpcGl0YXRpb24iCmNvbG5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIpW2NvbG5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIpPT0iUHJlY2lwaXRhdGlvbi5zZWFzb25hbGl0eS4uQy5vZi5WLiJdIDwtICJQcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHkiCgoKTXlkYXRhPC1tZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yWyxjKDE6Nyw5OjExLDE3LDE4LDIwLDIyLDI0KV0KY29sbmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvMikKTXlkYXRhJExhdCA8LSBzY2FsZShNeWRhdGEkTGF0KQpNeWRhdGEkTG9uZyA8LSBzY2FsZShNeWRhdGEkTG9uZykKTXlkYXRhJEFubnVhbFByZWNpcGl0YXRpb24gPC0gc2NhbGUoTXlkYXRhJEFubnVhbFByZWNpcGl0YXRpb24pCk15ZGF0YSRBbm51YWxNZWFuVGVtcGVyYXR1cmUgPC0gc2NhbGUoTXlkYXRhJEFubnVhbE1lYW5UZW1wZXJhdHVyZSkKTXlkYXRhJFByZWNpcGl0YXRpb25TZWFzb25hbGl0eSA8LSBzY2FsZShNeWRhdGEkUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5KQpNeWRhdGEkVGVtcGVyYXR1cmVTZWFzb25hbGl0eSAgPC0gc2NhbGUoTXlkYXRhJFRlbXBlcmF0dXJlU2Vhc29uYWxpdHkpCk15ZGF0YSRNZWFuRGl1cm5hbFRlbXBlcmF0dXJlUmFuZ2U8LSBzY2FsZShNeWRhdGEkTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlKQpNeWRhdGEkTWluVGVtcGVyYXR1cmUgPC0gc2NhbGUoTXlkYXRhJE1pblRlbXBlcmF0dXJlKQpNeWRhdGEkTWF4VGVtcGVyYXR1cmUgPC0gc2NhbGUoTXlkYXRhJE1heFRlbXBlcmF0dXJlKQoKCgptb2QzPC1sbShtZWFuLkZ1bmN0aW9uLkFscGhhLmRpdiB+IExhdCArIExvbmcgKyBBbm51YWxQcmVjaXBpdGF0aW9uICsgQW5udWFsTWVhblRlbXBlcmF0dXJlICsgUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5ICsgVGVtcGVyYXR1cmVTZWFzb25hbGl0eSAgKyBNZWFuRGl1cm5hbFRlbXBlcmF0dXJlUmFuZ2UrIE1pblRlbXBlcmF0dXJlICsgTWF4VGVtcGVyYXR1cmUgLCBkYXRhID0gTXlkYXRhKQoKY2FyOjpxcXAobWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvMiRtZWFuLkZ1bmN0aW9uLkFscGhhLmRpdiwgIm5vcm0iKQpwbG90KGRlbnNpdHkobWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvMiRtZWFuLkZ1bmN0aW9uLkFscGhhLmRpdikpCnNoYXBpcm8udGVzdChtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8yJG1lYW4uRnVuY3Rpb24uQWxwaGEuZGl2KQpicHRlc3QobW9kMykKcGxvdChtb2QzKQpzdW1tYXJ5KG1vZDMpCiMgSXMgZW5kb3BoeXRlIGRpdmVyc2l0eSBkcml2ZW4gYnkgYW55IGNsaW1hdGljIGRhdGE/IE5PCm1vZDMubUxhdDwtdXBkYXRlKG1vZDMsLn4uIC0gTGF0KQphbm92YShtb2QzLG1vZDMubUxhdCkKCm1vZDMubUxvbmc8LXVwZGF0ZShtb2QzLm1MYXQsLn4uIC0gTG9uZykKYW5vdmEobW9kMy5tTGF0LG1vZDMubUxvbmcpCgojIEFubnVhbCBwcmVjaXBpdGF0aW9uIGlzIHNpZ25pZmljYW50ISAKbW9kMy5tQW5udWFsUHJlY2lwaXRhdGlvbjwtdXBkYXRlKG1vZDMubUxvbmcsLn4uIC0gQW5udWFsUHJlY2lwaXRhdGlvbikKYW5vdmEobW9kMy5tTG9uZyxtb2QzLm1Bbm51YWxQcmVjaXBpdGF0aW9uKQoKbW9kMy5tQW5udWFsTWVhblRlbXBlcmF0dXJlPC11cGRhdGUobW9kMy5tTG9uZywufi4gLSBBbm51YWxNZWFuVGVtcGVyYXR1cmUpCmFub3ZhKG1vZDMubUxvbmcsbW9kMS5tQW5udWFsTWVhblRlbXBlcmF0dXJlKQoKbW9kMy5tUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5PC11cGRhdGUobW9kMy5tQW5udWFsTWVhblRlbXBlcmF0dXJlLC5+LiAtIFByZWNpcGl0YXRpb25TZWFzb25hbGl0eSkKYW5vdmEobW9kMy5tQW5udWFsTWVhblRlbXBlcmF0dXJlLCBtb2QzLm1QcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHkpCgojIFRlbXBlcmF0dXJlIHNlYXNvbmFsaXR5IGlzIHNpZ25pZmljYW50IQptb2QzLm1UZW1wZXJhdHVyZVNlYXNvbmFsaXR5PC11cGRhdGUobW9kMy5tUHJlY2lwaXRhdGlvblNlYXNvbmFsaXR5LC5+LiAtIFRlbXBlcmF0dXJlU2Vhc29uYWxpdHkpCmFub3ZhKG1vZDMubVByZWNpcGl0YXRpb25TZWFzb25hbGl0eSxtb2QzLm1UZW1wZXJhdHVyZVNlYXNvbmFsaXR5KQoKbW9kMy5tTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlPC11cGRhdGUobW9kMy5tVGVtcGVyYXR1cmVTZWFzb25hbGl0eSwufi4gLSBNZWFuRGl1cm5hbFRlbXBlcmF0dXJlUmFuZ2UpCmFub3ZhKG1vZDMubVRlbXBlcmF0dXJlU2Vhc29uYWxpdHksIG1vZDMubU1lYW5EaXVybmFsVGVtcGVyYXR1cmVSYW5nZSkKCiMgTWluIHRlbXBlcmF0dXJlIGlzIGEgU0xJR0hUTFkgc2lnbmlmaWNhbnQgcHJlZGljdG9yIQptb2QzLm1NaW5UZW1wZXJhdHVyZTwtdXBkYXRlKG1vZDMubU1lYW5EaXVybmFsVGVtcGVyYXR1cmVSYW5nZSwufi4gLSBNaW5UZW1wZXJhdHVyZSkKYW5vdmEobW9kMy5tTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlLCBtb2QzLm1NaW5UZW1wZXJhdHVyZSkKCgptb2QzLm1NYXhUZW1wZXJhdHVyZTwtdXBkYXRlKG1vZDMubU1pblRlbXBlcmF0dXJlLC5+LiAtIE1heFRlbXBlcmF0dXJlKQphbm92YShtb2QzLm1NaW5UZW1wZXJhdHVyZSwgbW9kMy5tTWF4VGVtcGVyYXR1cmUpCgptb2Q0PC0gbG0oRnVuY3Rpb24uQWxwaGEuZGl2flNwZWNpZXMsZGF0YT1tZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8pCnN1bW1hcnkobW9kNCkKYGBgCgoKIyMjIENvbXBvc2l0aW9uIG1vZGVsCmBgYHtyIG11bHRpdmFyaWF0ZSBtb2RlbCBGVU59Clg8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mb1ssYygxLDMpXQptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMjwtbWV0YWdlbm9tZV9wcmVkaWN0aW9ucwptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiRTYW1wbGVJRDwtcm93Lm5hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMpCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMyPC1tZXJnZShtZXRhZ2Vub21lX3ByZWRpY3Rpb25zMixYLCBieT0iU2FtcGxlSUQiKQptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiRTcGVjaWVzPC1hcy5mYWN0b3IobWV0YWdlbm9tZV9wcmVkaWN0aW9uczIkU3BlY2llcykKCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMyPC1hZ2dyZWdhdGUobWV0YWdlbm9tZV9wcmVkaWN0aW9uczIsIGJ5ID0gbGlzdChzcGVjaWVzPW1ldGFnZW5vbWVfcHJlZGljdGlvbnMyJFNwZWNpZXMpLCBGVU49bWVhbikKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczIkU2FtcGxlSUQ8LU5VTEwKCnJvdy5uYW1lcyhtZXRhZ2Vub21lX3ByZWRpY3Rpb25zMik8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnMyJHNwZWNpZXMKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczIkU3BlY2llczwtTlVMTAptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiRzcGVjaWVzPC1OVUxMCnN1bShpcy5uYShtZXRhZ2Vub21lX3ByZWRpY3Rpb25zMikpCgptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMm1hdGNoZWQ8LW1ldGFnZW5vbWVfcHJlZGljdGlvbnMyW21hdGNoKHJvd25hbWVzKGRpc3RfbWF0cml4KSwgcm93bmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9uczIpKSwgXQpiZXRhX2Rpdk1hdDwtIHZlZ2Rpc3QobWV0YWdlbm9tZV9wcmVkaWN0aW9uczJtYXRjaGVkLCAiYnJheSIsZGlhZz1UKQoKCiMgQXJlIHRoZSBlbmRvcGh5dGVzIG1vcmUgc2ltaWxhciBpbiBzcGVjaWVzIHRoYXQgYXJlIG1vcmUgY2xvc2VseSByZWxhdGVkIHBoeWxvZ2VuaWNhbGx5PyBOTyEgCm1hbnRlbChiZXRhX2Rpdk1hdCxkaXN0X21hdHJpeCkKCiMgYXJlIHNpbWlsYXJpdHkgaW4gdGhlIGVuZG9waHl0ZSBjb21wb3NpdGlvbiBkcml2ZW4gYnkgY2xpbWF0ZSBkYXRhPwoKCk15ZGF0YSRTcGVjaWVzPC1wbHlyOjpyZXZhbHVlKE15ZGF0YSRTcGVjaWVzLCBjKCJCcmFzc2ljYV9uYXB1cyI9IkJyYXNzaWNhIG5hcHVzIiwgIkJyYXNzaWNhX29sZXJhY2VhIj0iQnJhc3NpY2Egb2xlcmFjZWEiLCJDcmF0b25ldXJvbiI9IkNyYXRvbmV1cm9uIGZpbGljaW51bSIsIkdyaW1taWEiPSJHcmltbWlhIHBpbGlmZXJhIiwiTWljcm9kZXNtaXMiPSJNaWNyb2Rlc21pcyBjYXNlYXJpaWZvbGlhIiwiT3JjaGlkIj0iUGhhbGFlbm9wc2lzIiwiT3J5emEiPSJPcnl6YSBzYXRpdmEiLCJQYWVvbmlhX3JvY2tpaSI9IlBhZW9uaWEgcm9ja2lpIiwiUGFlb25pYV9zdWZmcnV0aWNvc2EiPSJQYWVvbmlhIHN1ZmZydXRpY29zYSIsIlBpbnVzIj0iUGludXMgcGluYXN0ZXIiLCJQaW51c19mbGV4aWxpcyI9IlBpbnVzIGZsZXhpbGlzIiwiUHlsYWlzaWVsbGEiPSJQeWxhaXNpYSBwb2x5YW50aGEiLCJSb3RobWFubmlhIj0iUm90aG1hbm5pYSBtYWNyb3BoeWxsYSIsIlNhbnRpcmlhIj0iU2FudGlyaWEgYXBpY3VsYXRhIiwiU29sYW51bSI9IlNvbGFudW0gbHljb3BlcnNpY3VtIiwiVml0aXMiPSJWaXRpcyB2aW5pZmVyYSIsIlplYSI9IlplYSBtYXlzIikpCnJvd25hbWVzKE15ZGF0YSk8LU15ZGF0YSRTcGVjaWVzCgoKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczIkc3BlY2llczwtcm93bmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9uczIpCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMyJHNwZWNpZXM8LWFzLmZhY3RvcihtZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiRzcGVjaWVzKQptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiRzcGVjaWVzPC1wbHlyOjpyZXZhbHVlKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMyJHNwZWNpZXMsIGMoIkJyYXNzaWNhX25hcHVzIj0iQnJhc3NpY2EgbmFwdXMiLCAiQnJhc3NpY2Ffb2xlcmFjZWEiPSJCcmFzc2ljYSBvbGVyYWNlYSIsIkNyYXRvbmV1cm9uIj0iQ3JhdG9uZXVyb24gZmlsaWNpbnVtIiwiR3JpbW1pYSI9IkdyaW1taWEgcGlsaWZlcmEiLCJNaWNyb2Rlc21pcyI9Ik1pY3JvZGVzbWlzIGNhc2VhcmlpZm9saWEiLCJPcmNoaWQiPSJQaGFsYWVub3BzaXMiLCJPcnl6YSI9Ik9yeXphIHNhdGl2YSIsIlBhZW9uaWFfcm9ja2lpIj0iUGFlb25pYSByb2NraWkiLCJQYWVvbmlhX3N1ZmZydXRpY29zYSI9IlBhZW9uaWEgc3VmZnJ1dGljb3NhIiwiUGludXMiPSJQaW51cyBwaW5hc3RlciIsIlBpbnVzX2ZsZXhpbGlzIj0iUGludXMgZmxleGlsaXMiLCJQeWxhaXNpZWxsYSI9IlB5bGFpc2lhIHBvbHlhbnRoYSIsIlJvdGhtYW5uaWEiPSJSb3RobWFubmlhIG1hY3JvcGh5bGxhIiwiU2FudGlyaWEiPSJTYW50aXJpYSBhcGljdWxhdGEiLCJTb2xhbnVtIj0iU29sYW51bSBseWNvcGVyc2ljdW0iLCJWaXRpcyI9IlZpdGlzIHZpbmlmZXJhIiwiWmVhIj0iWmVhIG1heXMiKSkKcm93bmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9uczIpPC1tZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiRzcGVjaWVzCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMyJHNwZWNpZXM8LU5VTEwKCgptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMi5oZWxsIDwtIGRlY29zdGFuZChtZXRhZ2Vub21lX3ByZWRpY3Rpb25zMiwgImhlbGwiKQoKCk15ZGF0YTwtTXlkYXRhW21hdGNoKHJvd25hbWVzKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMyKSwgcm93bmFtZXMoTXlkYXRhKSksIF0KdmFyIDwtTXlkYXRhWyxjKDQ6MTUpXQoKZm9ybXVsYVJEQTwtIHJkYShtZXRhZ2Vub21lX3ByZWRpY3Rpb25zMi5oZWxsIH4gTGF0ICAgKyBQcmVjaXBpdGF0aW9uU2Vhc29uYWxpdHkgKyBUZW1wZXJhdHVyZVNlYXNvbmFsaXR5ICsgTWluVGVtcGVyYXR1cmUgKyBNYXhUZW1wZXJhdHVyZSsgTWF4UHJlY2lwaXRhdGlvbiArIENvbGRlc3RQcmVjaXBpdGF0aW9uLCBkYXRhPXZhciwgc2NhbGU9RikKCmhlYWQoc3VtbWFyeShmb3JtdWxhUkRBKSkKUnNxdWFyZUFkaihmb3JtdWxhUkRBKQphbm92YShmb3JtdWxhUkRBLCBwZXJtdXRhdGlvbnM9MTAwMCkKYW5vdmFNQVJHSU48LWFub3ZhLmNjYShmb3JtdWxhUkRBLCBieT0ibWFyZ2luIiwgcGVybXV0YXRpb25zPTEwMDApCgoKCnZhcnBhcnQobWV0YWdlbm9tZV9wcmVkaWN0aW9uczIuaGVsbCwgfkxhdCArIExvbmcsIH4gQW5udWFsTWVhblRlbXBlcmF0dXJlICsgTWVhbkRpdXJuYWxUZW1wZXJhdHVyZVJhbmdlICsgVGVtcGVyYXR1cmVTZWFzb25hbGl0eSArIE1heFRlbXBlcmF0dXJlICsgTWluVGVtcGVyYXR1cmUsIH4gQW5udWFsUHJlY2lwaXRhdGlvbiArIFByZWNpcGl0YXRpb25TZWFzb25hbGl0eSArIE1heFByZWNpcGl0YXRpb24rIE1pblByZWNpcGl0YXRpb24gKyBDb2xkZXN0UHJlY2lwaXRhdGlvbiwgZGF0YT12YXIpCmBgYAoKIyMgRklHVVJFUwoKYGBge3J9Cm1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIkU3BlY2llczwtYXMuZmFjdG9yKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIkU3BlY2llcykKbWV0YWdlbm9tZV9wcmVkaWN0aW9ucy5pbmZvMiRTcGVjaWVzPC1wbHlyOjpyZXZhbHVlKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMuaW5mbzIkU3BlY2llcywgYygiQnJhc3NpY2FfbmFwdXMiPSJCcmFzc2ljYSBuYXB1cyIsICJCcmFzc2ljYV9vbGVyYWNlYSI9IkJyYXNzaWNhIG9sZXJhY2VhIiwiQ3JhdG9uZXVyb24iPSJDcmF0b25ldXJvbiBmaWxpY2ludW0iLCJHcmltbWlhIj0iR3JpbW1pYSBwaWxpZmVyYSIsIk1pY3JvZGVzbWlzIj0iTWljcm9kZXNtaXMgY2FzZWFyaWlmb2xpYSIsIk9yY2hpZCI9IlBoYWxhZW5vcHNpcyIsIk9yeXphIj0iT3J5emEgc2F0aXZhIiwiUGFlb25pYV9yb2NraWkiPSJQYWVvbmlhIHJvY2tpaSIsIlBhZW9uaWFfc3VmZnJ1dGljb3NhIj0iUGFlb25pYSBzdWZmcnV0aWNvc2EiLCJQaW51cyI9IlBpbnVzIHBpbmFzdGVyIiwiUGludXNfZmxleGlsaXMiPSJQaW51cyBmbGV4aWxpcyIsIlB5bGFpc2llbGxhIj0iUHlsYWlzaWEgcG9seWFudGhhIiwiUm90aG1hbm5pYSI9IlJvdGhtYW5uaWEgbWFjcm9waHlsbGEiLCJTYW50aXJpYSI9IlNhbnRpcmlhIGFwaWN1bGF0YSIsIlNvbGFudW0iPSJTb2xhbnVtIGx5Y29wZXJzaWN1bSIsIlZpdGlzIj0iVml0aXMgdmluaWZlcmEiLCJaZWEiPSJaZWEgbWF5cyIpKQoKCiMgQWxwaGEgdG8gc2VjaWVzCkFkaXZfc3BlY2llc19GVU48LWdncGxvdChtZXRhZ2Vub21lX3ByZWRpY3Rpb25zLmluZm8sIGFlcyh5PUZ1bmN0aW9uLkFscGhhLmRpdix4PVNwZWNpZXMpKSsKICBnZW9tX2JveHBsb3QoYWVzKGNvbG9yPVNwZWNpZXMpKSsKICBsYWJzKHk9IlNoYW5ub24gZGl2ZXJzaXR5IikrCiAgdGhlbWVfa2F0aGVyaW5lKCkrIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSksbGVnZW5kLnBvc2l0aW9uPSJub25lIikrCiAgZ2d0aXRsZSgiQWxwaGEgRGl2ZXJzaXR5IG9mIEZ1bmN0aW9ucyBieSBTcGVjaWVzIikKZ2dzYXZlKCJBZGl2X3NwZWNpZXMuRlVOX1BMT1QucGRmIixBZGl2X3NwZWNpZXNfRlVOKQoKIyBSREEKc21yeSA8LSBzdW1tYXJ5KGZvcm11bGFSREEpCmRmMSAgPC0gZGF0YS5mcmFtZShzbXJ5JHNpdGVzWywxOjJdKSAgICAgICAjIFBDMSBhbmQgUEMyCmRmMiAgPC0gZGF0YS5mcmFtZShzbXJ5JGJpcGxvdFssMToyXSkgICAgICMgbG9hZGluZ3MgZm9yIFBDMSBhbmQgUEMyCnJkYS5wbG90IDwtIGdncGxvdChkZjEsIGFlcyh4PVJEQTEsIHk9UkRBMikpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yb3duYW1lcyhkZjEpKSxzaXplPTMscG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoPS4yLGhlaWdodD0uMikpICsKICBnZW9tX3BvaW50KGFlcyhhbHBoYT0wLjMpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkb3R0ZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkb3R0ZWQiKSAgCnJvd25hbWVzKGRmMikKbmFtZXM8LWMoIkxhdGl0dWRlIiwgIlByZWNpcGl0YXRpb24gU2Vhc29uYWxpdHkiLCAiVGVtcGVyYXR1cmUgU2Vhc29uYWxpdHkiLCAiTWluIFRlbXBlcmF0dXJlIiwgIk1heCBUZW1wZXJhdHVyZSIsICJNYXggUHJlY2lwaXRhdGlvbiIsICJDb2xkZXN0IFByZWNpcGl0YXRpb25cbiIpCgooZm9ybXVsYVJEQS5GVU5QTE9UPC1yZGEucGxvdCArCiAgZ2VvbV9zZWdtZW50KGRhdGE9ZGYyLCBhZXMoeD0wLCB4ZW5kPVJEQTEsIHk9MCwgeWVuZD1SREEyKSwgCiAgICAgICAgICAgICAgIGNvbG9yPSJyZWQiLCBhcnJvdz1hcnJvdyhsZW5ndGg9dW5pdCgwLjAxLCJucGMiKSkpICsKICBnZW9tX3RleHQoZGF0YT1kZjIsIAogICAgICAgICAgICBhZXMoeD1SREExLHk9UkRBMixsYWJlbD1uYW1lcywKICAgICAgICAgICAgICAgIGhqdXN0PTAuNSooMS1zaWduKFJEQTEpKSx2anVzdD0wLjUqKDEtc2lnbihSREEyKSkpLCAKICAgICAgICAgICAgY29sb3I9InJlZCIsIHNpemU9NCkrCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xLjEsIDAuOCkseGxpbSA9IGMoLTEsIDEpKSArdGhlbWVfa2F0aGVyaW5lKCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKQpnZ3NhdmUoImZvcm11bGFSREEuRlVOX1BMT1QucGRmIixmb3JtdWxhUkRBLkZVTlBMT1QpCgojIE5NRFMKI01ha2UgYSBtYXRyaXggd2l0aCBubyByb3cgb3IgY29sdW1uIGVxdWFsIHRvIDAgKGRvIG5vdCBlbmNsdWRlIHRoZSBlbnYgdmFyaWFibGUgKEdNIENPVkVSQUdFKSkKbWV0YWdlbm9tZV9wcmVkaWN0aW9ucyRTYW1wbGVJRDwtcm93bmFtZXMobWV0YWdlbm9tZV9wcmVkaWN0aW9ucykKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczM8LW1lcmdlKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMsWCwgYnk9IlNhbXBsZUlEIikKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczMkU2FtcGxlSUQ8LU5VTEwKbWV0YWdlbm9tZV9wcmVkaWN0aW9uczMkU3BlY2llczwtYXMuZmFjdG9yKG1ldGFnZW5vbWVfcHJlZGljdGlvbnMzJFNwZWNpZXMpCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMzJFNwZWNpZXM8LXBseXI6OnJldmFsdWUobWV0YWdlbm9tZV9wcmVkaWN0aW9uczMkU3BlY2llcywgYygiQnJhc3NpY2FfbmFwdXMiPSJCcmFzc2ljYSBuYXB1cyIsICJCcmFzc2ljYV9vbGVyYWNlYSI9IkJyYXNzaWNhIG9sZXJhY2VhIiwiQ3JhdG9uZXVyb24iPSJDcmF0b25ldXJvbiBmaWxpY2ludW0iLCJHcmltbWlhIj0iR3JpbW1pYSBwaWxpZmVyYSIsIk1pY3JvZGVzbWlzIj0iTWljcm9kZXNtaXMgY2FzZWFyaWlmb2xpYSIsIk9yY2hpZCI9IlBoYWxhZW5vcHNpcyIsIk9yeXphIj0iT3J5emEgc2F0aXZhIiwiUGFlb25pYV9yb2NraWkiPSJQYWVvbmlhIHJvY2tpaSIsIlBhZW9uaWFfc3VmZnJ1dGljb3NhIj0iUGFlb25pYSBzdWZmcnV0aWNvc2EiLCJQaW51cyI9IlBpbnVzIHBpbmFzdGVyIiwiUGludXNfZmxleGlsaXMiPSJQaW51cyBmbGV4aWxpcyIsIlB5bGFpc2llbGxhIj0iUHlsYWlzaWEgcG9seWFudGhhIiwiUm90aG1hbm5pYSI9IlJvdGhtYW5uaWEgbWFjcm9waHlsbGEiLCJTYW50aXJpYSI9IlNhbnRpcmlhIGFwaWN1bGF0YSIsIlNvbGFudW0iPSJTb2xhbnVtIGx5Y29wZXJzaWN1bSIsIlZpdGlzIj0iVml0aXMgdmluaWZlcmEiLCJaZWEiPSJaZWEgbWF5cyIpKQoKcm93bmFtZXMuTTwtbWV0YWdlbm9tZV9wcmVkaWN0aW9uczMkU3BlY2llcwptZXRhZ2Vub21lX3ByZWRpY3Rpb25zMyRTcGVjaWVzPC1OVUxMCm1ldGFnZW5vbWVfcHJlZGljdGlvbnMzJFNhbXBsZUlEPC1OVUxMCk0gPC0gYXMubWF0cml4KG1ldGFnZW5vbWVfcHJlZGljdGlvbnMzKQpNW2lzLm5hKE0pXSA8LSAwCndoaWNoKCBjb2xTdW1zKE0pPT0wICkKd2hpY2goIHJvd1N1bXMoTSk9PTAgKQoKcm93bmFtZXMoTSkgPC0gcm93bmFtZXMuTQoKZGlzdF9NIDwtIHZlZ2Rpc3QoTSwgbWV0aG9kID0gImJyYXkiLCBiaW5hcnkgPSBUKQoKCm1ldGEubm1kcyA8LSBtZXRhTURTKGRpc3RfTSwgaz0yLCB0cnltYXggPSAzMDAwKQpzdHIobWV0YS5ubWRzKQpzdHJlc3NwbG90KG1ldGEubm1kcykKClNwZWNpZXM8LWRhdGEuZnJhbWUoU3BlY2llcz1hcy5mYWN0b3Iocm93bmFtZXMuTSkpCiMgZW52Zml0CmVudmZpdCA8LSBlbnZmaXQobWV0YS5ubWRzLCBlbnYgPSBTcGVjaWVzLCBwZXJtID0gOTk5KSAjc3RhbmRhcmQgZW52Zml0CmVudmZpdAoKI2RhdGEgZm9yIHBsb3R0aW5nIAojI05NRFMgcG9pbnRzCk5NRFMuZGF0YTwtU3BlY2llcyAKTk1EUy5kYXRhJE5NRFMxPC1tZXRhLm5tZHMkcG9pbnRzWyAsMV0gCk5NRFMuZGF0YSROTURTMjwtbWV0YS5ubWRzJHBvaW50c1sgLDJdIApjb2xuYW1lcyhOTURTLmRhdGEpWzFdIDwtICJTcGVjaWVzIgoKbXVsdCA8LSAxICNtdWx0aXBsaWVyIGZvciB0aGUgYXJyb3dzIGFuZCB0ZXh0IGZvciBlbnZmaXQgYmVsb3cuIFlvdSBjYW4gY2hhbmdlIHRoaXMgYW5kIHRoZW4gcmVydW4gdGhlIHBsb3QgY29tbWFuZC4KCihGVU5DTE9TRS5ubWRzLmdnMSA8LSBnZ3Bsb3QoZGF0YSA9IE5NRFMuZGF0YSwgYWVzKHkgPSBOTURTMiwgeCA9IE5NRFMxKSkrIAogICAgZ2VvbV9wb2ludCggYWVzKGNvbG9yID0gTk1EUy5kYXRhJFNwZWNpZXMpLCBzaXplID0gMS41LGFscGhhPTAuNikrIAogICAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC0wLjIsMC4xKSx5bGltID0gYygtMC4wNywwLjAyNSkpICsgCiAgICB0aGVtZV9rYXRoZXJpbmUoKSkKZ2dzYXZlKCJubWRzLkZVTl9QTE9UQ0xPU0UucGRmIixGVU5DTE9TRS5ubWRzLmdnMSkKCihGVU5GQVIubm1kcy5nZzEgPC0gZ2dwbG90KGRhdGEgPSBOTURTLmRhdGEsIGFlcyh5ID0gTk1EUzIsIHggPSBOTURTMSkpKyAKICAgIGdlb21fcG9pbnQoIGFlcyhjb2xvciA9IE5NRFMuZGF0YSRTcGVjaWVzKSwgc2l6ZSA9IDEuNSxhbHBoYT0wLjYpKyAKICAgIHRoZW1lX2thdGhlcmluZSgpKQpnZ3NhdmUoIm5tZHMuRlVOX1BMT1RGQVIucGRmIixGVU5GQVIubm1kcy5nZzEpCmBgYA==